/* Copyright (c) 2008 Google Inc.
*  Copyright (c) 2009 Pierre Henri Kuate.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

using System.Collections.Generic;

namespace org.opensocial.data
{
    /// <summary> An object representing a single property of an OpenSocial entity. These
    /// properties may have a single value or multiple values and these values
    /// can either consist of simple character strings or complex entities;
    /// for example, the "name" field of a Person instance can be modeled
    /// as an OpenSocialObject with "givenName" and "familyName" fields.
    /// </summary>
    /// <author>  Jason Cooper
    /// </author>
    public class OpenSocialField
    {
        private readonly bool complex;
        private readonly IList<object> values;

        public OpenSocialField(bool complex)
        {
            this.complex = complex;

            values = new List<object>();
        }

        /// <summary> Returns the first stored value as a String. Returns null if no values
        /// have been associated with the instance.
        /// </summary>
        public string StringValue
        {
            get
            {
                if (values.Count == 0)
                    return null;

                if (IsComplex)
                    return values[0].ToString(); // TODO: Shouldn't it throw an exception?

                return (string) values[0];
            }
        }

        /// <summary> Returns the first stored value as an OpenSocialObject. Returns null if
        /// no values have been associated with the instance.
        /// 
        /// </summary>
        /// <throws>  OpenSocialException if the complex instance variable is false, </throws>
        /// <summary>         indicating that the values are stored as simple String objects.
        /// </summary>
        public OpenSocialObject Value
        {
            get
            {
                if (values.Count == 0)
                    return null;
                if (!IsComplex)
                    throw new OpenSocialException("String-based field cannot be returned as an OpenSocialObject");

                return (OpenSocialObject) values[0];
            }
        }

        /// <summary> Returns true if the number of stored values is greater than one, false
        /// otherwise.
        /// </summary>
        public bool IsMultivalued
        {
            get { return (values.Count > 1); }
        }

        /// <summary> Returns false if values are stored as simple String objects, true if
        /// OpenSocialObject instances are stored instead.
        /// </summary>
        public bool IsComplex
        {
            get { return complex; }
        }

        /// <summary> Stores passed object as a value.</summary>
        public void addValue(object o)
        {
            values.Add(o);
        }

        /// <summary> Returns all stored values as a Java Collection of String objects.</summary>
        public IList<string> getStringValues()
        {
            IList<string> stringCollection =
                new List<string>(values.Count);

            foreach (object o in values)
            {
                if (IsComplex)
                {
                    stringCollection.Add(o.ToString());
                }
                else if (o is IList<string>)
                {
                    return (IList<string>)o;
                }
                else
                {
                    stringCollection.Add((string)o);
                }
            }

            return stringCollection;
        }

        /// <summary> Returns all stored values as a Collection of String array objects.</summary>
        public IList<string[]> getStringArrayValues()
        {
            IList<string[]> stringCollection = new List<string[]>(values.Count);

            foreach (object o in values)
            {
                if (o is IList<string[]>)
                {
                    return (IList<string[]>)o;
                }
            }

            return stringCollection;
        }

        /// <summary> Returns all stored values as a Collection of string dictionary objects.</summary>
        public Dictionary<string, string> getStringDictionaryValues()
        {
            Dictionary<string, string> stringCollection = new Dictionary<string, string>(values.Count);

            foreach (object o in values)
            {
                if (o is Dictionary<string, string>)
                {
                    return (Dictionary<string, string>)o;
                }
            }

            return stringCollection;
        }

        /// <summary> Returns all stored values as a Java Collection of OpenSocialObject instances.
        /// </summary>
        /// <throws>  OpenSocialException if the complex instance variable is false, </throws>
        /// <summary>         indicating that the values are stored as simple String objects.
        /// </summary>
        public IList<OpenSocialObject> getValues()
        {
            if (!IsComplex)
            {
                throw new OpenSocialException("String-based fields cannot be returned as an OpenSocialObject " +
                                              "collection");
            }

            IList<OpenSocialObject> objectCollection =
                new List<OpenSocialObject>(values.Count);

            foreach (object o in values)
            {
                objectCollection.Add((OpenSocialObject) o);
            }

            return objectCollection;
        }
    }
}